package com.nacos.shangtu.handler;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.nacos.shangtu.entity.dto.ChatMessage;
import com.nacos.shangtu.entity.dto.MessageDto;
import com.nacos.shangtu.entity.po.GroupPO;
import com.nacos.shangtu.entity.po.MessagePO;
import com.nacos.shangtu.entity.po.RecordPO;
import com.nacos.shangtu.entity.po.UserPO;
import com.nacos.shangtu.exception.BadRequestException;
import com.nacos.shangtu.service.GroupService;
import com.nacos.shangtu.service.MessageService;
import com.nacos.shangtu.service.RecordService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final ConcurrentHashMap<String, Channel> userChanelMapping = new ConcurrentHashMap<>();

    private MessageService messageService;

    private GroupService groupService;

    private RecordService recordService;

    public WebSocketFrameHandler(MessageService messageService, GroupService groupService, RecordService recordService) {
        this.messageService = messageService;
        this.groupService = groupService;
        this.recordService = recordService;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
        String data = frame.text();
        ChatMessage chatMessage = JSON.parseObject(data, ChatMessage.class);
        switch (chatMessage.getAction()) {
            case "login":
                doLogin(ctx, chatMessage);
                break;
            case "create":
                createConversation(chatMessage);
                break;
            case "chat":
                sendMessage(chatMessage);
                break;
            default:
                throw new BadRequestException("error action");
        }
    }

    private void sendMessage(ChatMessage chatMessage) {
        preCheck(chatMessage);
        chatMessage.setCreateTime(new Date());
        MessagePO messagePO = new MessagePO();
        BeanUtils.copyProperties(chatMessage, messagePO);
        messageService.save(messagePO);
        GroupPO groupPO = groupService.findGroupById(chatMessage.getGroupId()).orElse(new GroupPO());
        List<UserPO> users = groupService.findUsersByGroupId(chatMessage.getGroupId());
        UserPO fromUser = users.stream().filter(o -> StringUtils.equals(o.getUserId(), chatMessage.getFrom()))
                .findFirst().orElse(new UserPO());
        List<RecordPO> records = new ArrayList<>();
        for (UserPO user : users) {
            RecordPO recordPO = new RecordPO();
            recordPO.setMessageId(messagePO.getId());
            recordPO.setUserId(user.getUserId());
            Channel toUserChannel = userChanelMapping.get(user.getUserId());
            if (toUserChannel != null && toUserChannel.isActive()) {
                MessageDto messageDto = new MessageDto();
                messageDto.setGroupId(groupPO.getGroupId());
                messageDto.setGroupName(groupPO.getGroupName());
                messageDto.setFromUser(chatMessage.getFrom());
                messageDto.setFromUserAvatarUrl(fromUser.getAvatarUrl());
                messageDto.setFromUserName(fromUser.getUserName());
                if (StringUtils.equals(user.getUserId(), chatMessage.getFrom())) { // 本人
                    if (users.size() == 2) {
                        UserPO anotherUser = users.stream().filter(o -> !StringUtils.equals(o.getUserId(), user.getUserId())).findFirst().orElse(new UserPO());
                        messageDto.setToUser(anotherUser.getUserId());
                        messageDto.setToUserAvatarUrl(anotherUser.getAvatarUrl());
                        messageDto.setToUserName(anotherUser.getUserName());
                    }
                } else {
                    messageDto.setToUser(user.getUserId());
                    messageDto.setToUserAvatarUrl(user.getAvatarUrl());
                    messageDto.setToUserName(user.getUserName());
                }
                messageDto.setCreateTime(chatMessage.getCreateTime());
                messageDto.setContent(chatMessage.getContent());
                messageDto.setType(chatMessage.getType());
                toUserChannel.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(messageDto)));
                recordPO.setStatus(1); // 已发送
            } else {
                recordPO.setStatus(0);  // 未发送
            }
            records.add(recordPO);

        }
        recordService.save(records);
    }

    private void createConversation(ChatMessage chatMessage) {
        String groupId = createGroup(chatMessage);
        Channel toUserChannel = userChanelMapping.get(chatMessage.getFrom());
        if (toUserChannel != null && toUserChannel.isActive()) {
            List<UserPO> users = groupService.findUsersByGroupId(groupId);
            UserPO fromUser = users.stream().filter(o -> StringUtils.equals(o.getUserId(), chatMessage.getFrom()))
                    .findFirst().orElse(new UserPO());
            UserPO toUser = users.stream().filter(o -> StringUtils.equals(o.getUserId(), chatMessage.getTo()))
                    .findFirst().orElse(new UserPO());
            MessageDto messageDto = new MessageDto();
            messageDto.setGroupId(chatMessage.getGroupId());
            messageDto.setFromUser(chatMessage.getFrom());
            messageDto.setFromUserAvatarUrl(fromUser.getAvatarUrl());
            messageDto.setFromUserName(fromUser.getUserName());
            messageDto.setToUser(toUser.getUserId());
            messageDto.setToUserAvatarUrl(toUser.getAvatarUrl());
            messageDto.setToUserName(toUser.getUserName());
            messageDto.setCreateTime(chatMessage.getCreateTime());
            messageDto.setContent("");
            messageDto.setType("txt");
            messageDto.setGroupId(groupId);
            toUserChannel.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(messageDto)));
        }
    }

    private void doLogin(ChannelHandlerContext ctx, ChatMessage chatMessage) {
        userChanelMapping.put(chatMessage.getFrom(), ctx.channel());
        log.info("login user : {}", chatMessage.getFrom());
        // 推送未发送信息
        List<MessageDto> messages = messageService.findNotSendMessages(chatMessage.getFrom(), true);
        if (!CollectionUtils.isEmpty(messages)) {
            ctx.channel().writeAndFlush(new TextWebSocketFrame(JSONArray.toJSONString(messages)));
        }
    }

    private void preCheck(ChatMessage chatMessage) {
        if (StringUtils.isEmpty(chatMessage.getFrom())) {
            throw new BadRequestException("the from must be not empty.");
        }
        if (StringUtils.isEmpty(chatMessage.getGroupId()) && StringUtils.isEmpty(chatMessage.getTo())) {
            throw new BadRequestException("the to and GroupId can not be all empty.");
        }
        if (StringUtils.isNotEmpty(chatMessage.getGroupId())) {
            return;
        }
        List<String> userIds = List.of(chatMessage.getFrom(), chatMessage.getTo());
        if (StringUtils.isNotEmpty(chatMessage.getTo()) && StringUtils.isEmpty(chatMessage.getGroupId())) {
            Optional<GroupPO> optional=  groupService.findGroup(userIds);
            if (optional.isPresent()) {
                chatMessage.setGroupId(optional.get().getGroupId());
            } else {
                String groupId = groupService.createGroup(chatMessage.getFrom(), userIds, "");
                chatMessage.setGroupId(groupId);
            }

        }
    }

    private String createGroup(ChatMessage chatMessage) {
        if (StringUtils.isEmpty(chatMessage.getFrom()) && StringUtils.isEmpty(chatMessage.getTo())) {
            throw new BadRequestException("the from or to can not be empty.");
        }
        Optional<GroupPO> optional = groupService.findGroup(List.of(chatMessage.getFrom(), chatMessage.getTo()));
        if (optional.isPresent()) {
            return optional.get().getGroupId();
        } else {
            return groupService.createGroup(chatMessage.getFrom(), List.of(chatMessage.getFrom(), chatMessage.getTo()), "");
        }

    }


    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        userChanelMapping.values().removeIf(channel::equals);
        super.handlerRemoved(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
